#pragma once

#include <cstddef>
#include <stdint.h>

namespace hawking {
namespace indexlib {

inline size_t EncodedCountLength(size_t array_size) {
    if (array_size <= 0x0000003F) {
        return 1;
    }
    if (array_size <= 0x00003FFF) {
        return 2;
    }
    if (array_size <= 0x003FFFFF) {
        return 3;
    }
    return 4;
}

inline size_t EncodedCount(uint32_t array_size, char* buffer) {
    size_t len = EncodedCountLength(array_size);

    switch (len) {
    case 1: {
        ((uint8_t *)buffer)[0] = 0x00 | (uint8_t)array_size;
        break;
    }
    case 2: {
        ((uint8_t *)buffer)[0] = 0x40 | (uint8_t)((array_size >> 8) & 0xFF);
        ((uint8_t *)buffer)[1] = (uint8_t)(array_size & 0xFF);
        break;
    }
    case 3: {
        ((uint8_t *)buffer)[0] = 0x80 | (uint8_t)((array_size >> 16) & 0xFF);
        ((uint8_t *)buffer)[1] = (uint8_t)((array_size >> 8) & 0xFF);
        ((uint8_t *)buffer)[2] = (uint8_t)(array_size & 0xFF);
        break;
    }
    case 4: {
        ((uint8_t *)buffer)[0] = 0xC0 | (uint8_t)((array_size >> 24) & 0xFF);
        ((uint8_t *)buffer)[1] = (uint8_t)((array_size >> 16) & 0xFF);
        ((uint8_t *)buffer)[2] = (uint8_t)((array_size >> 8) & 0xFF);
        ((uint8_t *)buffer)[3] = (uint8_t)(array_size & 0xFF);
        break;
    }
    }
    
    return len;
}

inline uint32_t DecodeCount(const uint8_t* data, size_t* count_len) {
    uint8_t b = *(data++);
    uint8_t mask = b >> 6;
    uint32_t value = b & 0x3F;

    if (mask == 0) {
        *count_len = mask + 1;
        return value;
    }

    value = (value << 8) | *(data++);
    if (mask == 1) {
        *count_len = mask + 1;
        return value;
    }

    value = (value << 8) | *(data++);
    if (mask == 2) {
        *count_len = mask + 1;
        return value;
    }

    value = (value << 8) | *(data++);
    *count_len = mask + 1;
    return value;
}

}
}